<!--树形控件-->
<template>
	<div>
		<zh-input v-if="showSearch" v-model="searchValue" :delay="1000" placeholder="请输入查询内容" :suffix-icon="Search" />
		<div style="margin-top: 10px">
			<el-scrollbar :height="height" :maxMeight="maxMeight" :min-size="minSize">
				<el-tree
					ref="treeRef"
					:key="'treeKey' + treeKey"
					:data="treeList"
					:show-checkbox="showCheckbox"
					:render-after-expand="renderAfterExpand"
					:node-key="nodeKey"
					:draggable="draggable"
					:props="theProps"
					:indent="indent"
					:load="loadNode"
					:render-content="renderContent"
					:highlight-current="highlightCurrent"
					:default-expand-all="defaultExpandAll"
					:expand-on-click-node="expandOnClickNode"
					:check-on-click-node="checkOnClickNode"
					:auto-expand-parent="autoExpandParent"
					:default-expanded-keys="theExpandedKeys"
					:check-strictly="checkStrictly"
					:default-checked-keys="theSelectedKeys"
					:current-node-key="currentNodeKey"
					:filter-node-method="filterNode"
					:accordion="accordion"
					:icon="icon"
					:lazy="theLazy"
					:allow-drag="allowDrag"
					:allow-drop="allowDrop"
					@node-drop="onNodeDrop"
					@node-click="onNodeClick"
					@node-contextmenu="onNodeContextmenu"
					@check-change="onCheckChange"
					@check="onCheck"
					@current-change="onCurrentChange"
					@node-expand="onNodeExpand"
					@node-collapse="onNodeCollapse"
					@node-drag-start="onNodeDragStart"
					@node-drag-enter="onNodeDragEnter"
					@node-drag-leave="onNodeDragLeave"
					@node-drag-over="onNodeDragOver"
					@node-drag-end="onNodeDragEnd"
					><template v-slot:default="{ node }">
						<element-tree-line :node="node" :showLabelLine="showLabelLine" :indent="indent">
							<template v-slot:node-label>
								<span :style="{ fontSize: fontSize }" v-if="searchValue && node.label.indexOf(searchValue) > -1">
									{{ node.label.substr(0, node.label.indexOf(searchValue)) }}
									<span class="search-tree-color">{{ searchValue }}</span>
									{{ node.label.substr(node.label.indexOf(searchValue) + searchValue.length) }}
								</span>
								<span v-else :style="{ fontSize: fontSize }" :class="node.label == '加载更多' ? 'more-tree-color' : ''">
									{{ node.label }}
								</span>
								<div style="margin-left: 10px">
									<slot name="labelRight" :node="node"></slot>
								</div>
								<div style="margin-left: 10px">
									<slot name="button" :node="node"></slot>
								</div>
							</template>
						</element-tree-line>
					</template>
				</el-tree>
			</el-scrollbar>
		</div>
	</div>
</template>
<script lang="ts" setup name="zh-tree">
import { Search } from '@element-plus/icons-vue';
import type { ElTree } from 'element-plus';
import { getElementLabelLine } from './zh-tree-line';
import type Node from 'element-plus/es/components/tree/src/model/node';
import { loopExpandKeys } from '@/utils/util';
let ElementTreeLine = getElementLabelLine(h);
const prop = defineProps({
	maxMeight: [String, Number], //滚动条最大高度
	height: [String, Number], //滚动条高度
	minSize: Number, //滚动条最小尺寸
	data: Array, //展示数据
	emptyText: String, //内容为空的时候展示的文本
	nodeKey: {
		type: String,
		default: 'key',
	}, //每个树节点用来作为唯一标识的属性，整棵树应该是唯一的
	props: {
		//配置选项
		type: Object,
		default: function () {
			return {
				label: 'label',
				children: 'children',
				disabled: 'disabled',
				isLeaf: 'isLeaf',
				tag: 'tagName',
			};
		},
	},
	draggable: {
		//是否开启拖拽节点功能
		type: Boolean,
		default: false,
	},
	showSearch: {
		//是否显示查询框
		type: Boolean,
		default: true,
	},
	showCheckbox: {
		//节点是否可被选择
		type: Boolean,
		default: false,
	},
	nodeLevel: {
		//默认查询的节点级别
		type: Number,
		default: null,
	},
	renderAfterExpand: {
		//是否在第一次展开某个树节点后才渲染其子节点
		type: Boolean,
		default: true,
	},
	indent: {
		//相邻级节点间的水平缩进，单位为像素
		type: Number,
		default: 16,
	},
	load: Function, //加载子树数据的方法，仅当 lazy 属性为true 时生效
	renderContent: Function, //树节点的内容区的渲染 Function
	highlightCurrent: {
		//是否高亮当前选中节点，默认值是 true
		type: Boolean,
		default: true,
	},
	defaultExpandAll: {
		//是否高亮当前选中节点，默认值是 false
		type: Boolean,
		default: false,
	},
	expandOnClickNode: {
		//是否在点击节点的时候展开或者收缩节点， 默认值为 true，如果为 false，则只有点箭头图标的时候才会展开或者收缩节点。
		type: Boolean,
		default: true,
	},
	checkOnClickNode: {
		//是否在点击节点的时候选中节点，默认值为 false，即只有在点击复选框时才会选中节点。
		type: Boolean,
		default: false,
	},
	autoExpandParent: {
		//展开子节点的时候是否自动展开父节点
		type: Boolean,
		default: true,
	},
	defaultExpandedKeys: Array, //默认展开的节点的 key 的数组
	checkStrictly: {
		//在显示复选框的情况下，是否严格的遵循父子不互相关联的做法，默认为 false
		type: Boolean,
		default: false,
	},
	defaultCheckedKeys: Array, //默认勾选的节点的 key 的数组
	disabledList: {
		type: Array,
		default: function () {
			return [];
		},
	},
	currentNodeKey: [String, Number], //当前选中的节点
	filterNodeMethod: Function, //对树节点进行筛选时执行的方法， 返回 false 则表示这个节点会被隐藏
	accordion: {
		//是否每次只打开一个同级树节点展开
		type: Boolean,
		default: false,
	},
	icon: [String], //自定义图标组件
	lazy: {
		//是否懒加载子节点，需与 load 方法结合使用
		type: Boolean,
		default: false,
	},
	allowDrag: Function, //判断节点能否被拖拽 如果返回 false ，节点不能被拖动
	allowDrop: Function, //拖拽时判定目标节点能否成为拖动目标位置。 如果返回 false ，拖动节点不能被拖放到目标节点。 type 参数有三种情况：'prev'、'inner' 和 'next'，分别表示放置在目标节点前、插入至目标节点和放置在目标节点后
	url: String, //查询调用后台接口的url
	funcCode: String, //调用后台接口的功能编号
	queryParam: {
		//返回数据字段配置
		type: Object,
		default: function () {
			return {};
		},
	}, //调用后台接口的url
	moveUrl: String, //移动节点url
	moveFuncCode: String, //移动节点调用后台接口的功能编号
	searchField: {
		//查询提交到后台字段
		type: String,
		default: 'searchText',
	},
	showLabelLine: {
		//是否显示 label 的横线
		type: Boolean,
		default: false,
	},
	resultFields: {
		//返回数据字段配置
		type: Object,
		default: function () {
			return { treeList: 'treeList', expandedKeys: 'expandedKeys', selectedKeys: 'selectedKeys' };
		},
	},
	//是否加密
	cryptoEnabled: {
		type: Boolean,
		default: false,
	},
	//是否脱敏
	desensitizeFlag: {
		type: Boolean,
		default: false,
	},
	//是否防重复提交
	repeatEnabled: {
		type: Boolean,
		default: false,
	},
	//是否分页
	pagging: {
		type: Boolean,
		default: false,
	},
	//接口超时时间
	timeout: Number,
});
let theProps = ref({ label: 'label', children: 'children', disabled: 'disabled', isLeaf: 'isLeaf', tag: 'tagName', parentKey: 'parentKey' });
const theLazy = ref(prop.lazy);
//获取全局字体大小
const fontSize = ref('12px');
let treeKey = ref(1);
let globalComponentSize = ref($store.theme.globalComponentSize);
onBeforeMount(() => {
	if (prop.props) {
		let myProps = Object.assign(
			{ label: 'label', children: 'children', disabled: 'disabled', isLeaf: 'isLeaf', tag: 'tagName', parentKey: 'parentKey' },
			prop.props
		);
		theProps.value = myProps;
	}
	if (globalComponentSize.value === 'small') {
		fontSize.value = '12px';
	} else if (globalComponentSize.value === 'default') {
		fontSize.value = '14px';
	} else if (globalComponentSize.value === 'large') {
		fontSize.value = '18px';
	}
});

const searchValue = ref('');
const theExpandedKeys = ref(prop.defaultExpandedKeys);
const treeList = ref(prop.data);
const theSelectedKeys = ref(prop.defaultCheckedKeys);
const treeRef = ref<InstanceType<typeof ElTree>>();
let pageNumMap = ref(new Map());
watch(
	() => prop.data,
	(val) => {
		treeList.value = val;
	}
);
watch(
	() => prop.queryParam,
	() => {
		if (prop.queryParam.searchText) {
			theLazy.value = false;
		} else {
			theLazy.value = prop.lazy;
		}
		query();
	},
	{
		deep: true,
		immediate: false,
	}
);
watch(
	() => prop.defaultExpandedKeys,
	(val) => {
		theExpandedKeys.value = val;
	}
);
watch(
	() => prop.defaultCheckedKeys,
	(val) => {
		theSelectedKeys.value = val;
	}
);
watch(
	() => prop.lazy,
	(val) => {
		theLazy.value = val;
	}
);
//监听文本输入框
watch(
	searchValue,
	(val: any) => {
		if (prop.lazy) {
			if (val.value) {
				theLazy.value = false;
			} else {
				theLazy.value = true;
			}
			query();
		} else {
			treeRef.value!.filter(val);
		}
	},
	{
		deep: true,
		immediate: false,
	}
);
//数据过滤
const filterNode = (value: string, data: any) => {
	if (prop.filterNodeMethod) {
		return prop.filterNodeMethod(value, data);
	}
	if (!value) return true;
	return data[theProps.value.label].includes(value);
};
let resultFields = Object.assign({ treeList: 'treeList', expandedKeys: 'expandedKeys', selectedKeys: 'selectedKeys' }, prop.resultFields);
let level = ref(prop.nodeLevel);
if (prop.lazy && !level.value) {
	level.value = 2;
}
const loadNode = (node: Node, resolve) => {
	if (prop.url || prop.funcCode) {
		if (node.level === 0) {
			resolve(node.data);
		} else if (node.level < level.value) {
			let list = node.data[theProps.value.children] || [];
			list.forEach((element) => {
				if (prop.disabledList.includes(element.orgId)) {
					element.disabled = true;
				}
			});
			resolve();
		} else {
			if (searchValue.value || node.data.loaded) {
				let list = node.data[theProps.value.children] || [];
				list.forEach((element) => {
					if (prop.disabledList.includes(element.orgId)) {
						element.disabled = true;
					}
				});
				resolve(list);
			} else {
				const params: any = Object.assign({}, prop.queryParam);
				params[theProps.value.parentKey] = node.key;
				params.lazy = true;
				params.pageSize = 100;
				params.pageNum = 1;
				let url = '' as any;
				let config: any = {};
				if (prop.timeout && prop.timeout > 0) {
					config.timeout = prop.timeout;
				}
				let headers = {} as any;
				headers.cryptoEnabled = prop.cryptoEnabled;
				headers.repeatEnabled = prop.repeatEnabled;
				headers.desensitizeFlag = prop.desensitizeFlag;
				if (prop.funcCode) {
					headers['func-code'] = prop.funcCode;

					url = $api.common.send.url + prop.funcCode;
				} else {
					url = prop.url;
				}
				config.headers = headers;
				setTimeout(() => {
					$http
						.post(url, params, config)
						.then((res: any) => {
							let result = res.result;
							if (prop.pagging) {
								const list = result.list || [];
								list.forEach((element) => {
									if (prop.disabledList.includes(element.orgId)) {
										element.disabled = true;
									}
								});
								if (result.hasNextPage) {
									let obj = {
										moreFlag: true,
										lastNode: 1,
										isLeaf: true,
									};
									obj[theProps.value.label] = '加载更多';
									obj[prop.nodeKey] = 'more' + node.key;
									obj[theProps.value.parentKey] = node.key;
									list.push(obj);
									pageNumMap.value.set(node.key, 1);
								}
								resolve(list);
							} else {
								const list = result[resultFields.treeList] || [];
								list.forEach((element) => {
									if (prop.disabledList.includes(element.orgId)) {
										element.disabled = true;
									}
								});
								resolve(list);
							}
						})
						.catch(() => {
							resolve([]);
						});
				}, 50);
			}
		}
	} else {
		if (prop.load) {
			prop.load(node, resolve);
		}
	}
};

let query = () => {
	if (prop.url || prop.funcCode) {
		let params: any = {};
		if (prop.queryParam) {
			params = Object.assign({ lazy: theLazy.value }, prop.queryParam);
		}
		if (prop.showSearch) {
			params[prop.searchField] = searchValue.value;
		}
		if (!params[prop.searchField]) {
			params.nodeLevel = level.value;
		}
		if (prop.pagging) {
			params.pageSize = 100;
			params.pageNum = 1;
		}
		let url = '' as any;
		let config: any = {};
		if (prop.timeout && prop.timeout > 0) {
			config.timeout = prop.timeout;
		}
		let headers = {} as any;
		headers.cryptoEnabled = prop.cryptoEnabled;
		headers.repeatEnabled = prop.repeatEnabled;
		headers.desensitizeFlag = prop.desensitizeFlag;
		if (prop.funcCode) {
			headers['func-code'] = prop.funcCode;

			url = $api.common.send.url + prop.funcCode;
		} else {
			url = prop.url;
		}
		config.headers = headers;

		return $http
			.post(url, params, config)
			.then((res: any) => {
				let result = res.result;
				treeKey.value++;

				if (!prop.pagging) {
					let list = result[resultFields.treeList] || [];
					list.forEach((element) => {
						if (prop.disabledList.includes(element.orgId)) {
							element.disabled = true;
						}
					});

					treeList.value = list;
					let expandedKeys = [];
					loopExpandKeys(list, expandedKeys);
					if (expandedKeys.length <= 0) {
						expandedKeys = result[resultFields.expandedKeys] || [];
					}
					theExpandedKeys.value = expandedKeys;
					let selectedKeys = result[resultFields.selectedKeys];
					if (selectedKeys) {
						theSelectedKeys.value = selectedKeys || [];
					}
				} else {
					let list = result.list || [];
					list.forEach((element) => {
						if (prop.disabledList.includes(element.orgId)) {
							element.disabled = true;
						}
					});
					let theParentKey = params[theProps.value.parentKey];
					if (!theParentKey) {
						theParentKey = '#';
					}
					if (result.hasNextPage) {
						let obj = {
							moreFlag: true,
							lastNode: 1,
							isLeaf: true,
						};
						obj[theProps.value.label] = '加载更多';
						obj[prop.nodeKey] = 'more' + theParentKey;
						obj[theProps.value.parentKey] = theParentKey;
						list.push(obj);
						pageNumMap.value.set(theParentKey, 1);
					}
					pageNumMap.value.set(theParentKey, 1);
					treeList.value = list;
				}
			})
			.catch(() => {});
	}
};
const emits = defineEmits([
	'node-drop',
	'node-click',
	'node-contextmenu',
	'check-change',
	'check',
	'current-change',
	'node-expand',
	'node-collapse',
	'node-drag-start',
	'node-drag-enter',
	'node-drag-over',
	'node-drag-leave',
	'node-drag-end',
]);
let onNodeDrop = (node: any, dropNode: any, position: string, event: any) => {
	const dropKey = dropNode.key; //目标节点key
	const dragKey = node.key; //被拖拽节点key
	let dropPosition = 0;
	if (position === 'before') {
		dropPosition = -1;
	} else if (position === 'after') {
		dropPosition = 1;
	} else if (position === 'inner') {
		dropPosition = 0;
	}
	const params = { dropKey: dropKey, dragKey: dragKey, dropPosition: dropPosition };
	if (prop.moveUrl || prop.moveFuncCode) {
		let moveUrl = '' as any;
		let config: any = {};
		if (prop.timeout && prop.timeout > 0) {
			config.timeout = prop.timeout;
		}
		let headers = {} as any;
		headers.cryptoEnabled = prop.cryptoEnabled;
		headers.repeatEnabled = prop.repeatEnabled;
		headers.desensitizeFlag = prop.desensitizeFlag;
		if (prop.moveFuncCode) {
			headers['func-code'] = prop.moveFuncCode;

			moveUrl = $api.common.send.url + prop.moveFuncCode;
		} else {
			moveUrl = prop.moveUrl;
		}
		config.headers = headers;
		setTimeout(() => {
			$http
				.post(moveUrl, params, config)
				.then(() => {
					emits('node-drop', node, dropNode, position, event);
				})
				.catch(() => {
					//报错重新查询数据
					query();
				});
		}, 50);
	} else {
		emits('node-drop', node, dropNode, position, event);
	}
};
//当节点被点击的时候触发  三个参数：对应于节点点击的节点对象， TreeNode 节点 属性，事件对象
const onNodeClick = (...args: any[]) => {
	let node = args[0];
	if (node.moreFlag) {
		let pageNum = pageNumMap.value.get(node[theProps.value.parentKey]);
		pageNum = pageNum + 1;
		let params: any = {};
		if (prop.queryParam) {
			params = Object.assign({ lazy: theLazy.value }, prop.queryParam);
		}
		if (prop.showSearch) {
			params[prop.searchField] = searchValue.value;
		}
		if (!params[prop.searchField]) {
			params.nodeLevel = level.value;
		}
		params[theProps.value.parentKey] = node[theProps.value.parentKey];
		if (prop.pagging) {
			params.pageSize = 100;
			params.pageNum = pageNum;
		}

		let url = '' as any;
		let config: any = {};
		if (prop.timeout && prop.timeout > 0) {
			config.timeout = prop.timeout;
		}
		let headers = {} as any;
		headers.cryptoEnabled = prop.cryptoEnabled;
		headers.repeatEnabled = prop.repeatEnabled;
		headers.desensitizeFlag = prop.desensitizeFlag;
		if (prop.funcCode) {
			headers['func-code'] = prop.funcCode;

			url = $api.common.send.url + prop.funcCode;
		} else {
			url = prop.url;
		}
		config.headers = headers;
		setTimeout(() => {
			$http
				.post(url, params, config)
				.then((res: any) => {
					let result = res.result;
					const list = result.list || [];
					list.forEach((item) => {
						if (prop.disabledList.includes(item.orgId)) {
							item.disabled = true;
						}
						//在加载更多之前插入树节点
						treeRef.value!.insertBefore(item, node);
					});
					if (res.result.isLastPage) {
						treeRef.value!.remove(node);
					}
					//构造了请求之后，需要更新记录的pageNum值
					pageNumMap.value.set(node.parentId, pageNum);
				})
				.catch(() => {});
		}, 50);
	} else {
		emits('node-click', ...args);
	}
};
//当某一节点被鼠标右键点击时会触发该事件
//共四个参数，依次为：event、传递给 data 属性的数组中该节点所对应的对象、节点对应的 Node、节点组件本身。
const onNodeContextmenu = (...args: any[]) => {
	emits('node-contextmenu', ...args);
};
//当复选框被点击的时候触发
//	共三个参数，依次为：传递给 data 属性的数组中该节点所对应的对象、节点本身是否被选中、节点的子树中是否有被选中的节点
const onCheckChange = (...args: any[]) => {
	emits('check-change', ...args);
};
//点击节点复选框之后触发
//共两个参数，依次为：传递给 data 属性的数组中该节点所对应的对象、树目前的选中状态对象，包含 checkedNodes、checkedKeys、halfCheckedNodes、halfCheckedKeys 四个属性
const onCheck = (...args: any[]) => {
	emits('check', ...args);
};
//当前选中节点变化时触发的事件
//共两个参数，依次为：当前节点的数据，当前节点的 Node 对象
const onCurrentChange = (...args: any[]) => {
	emits('current-change', ...args);
};
//节点被展开时触发的事件
//共三个参数，依次为：传递给 data 属性的数组中该节点所对应的对象、节点对应的 Node、节点组件本身
const onNodeExpand = (...args: any[]) => {
	emits('node-expand', ...args);
};
//节点被关闭时触发的事件
//共三个参数，依次为：传递给 data 属性的数组中该节点所对应的对象、节点对应的 Node、节点组件本身
const onNodeCollapse = (...args: any[]) => {
	emits('node-collapse', ...args);
};
//节点开始拖拽时触发的事件
//共两个参数，依次为：被拖拽节点对应的 Node、event
const onNodeDragStart = (...args: any[]) => {
	emits('node-drag-start', ...args);
};
//拖拽进入其他节点时触发的事件
//共三个参数，依次为：被拖拽节点对应的 Node、所进入节点对应的 Node、event
const onNodeDragEnter = (...args: any[]) => {
	emits('node-drag-enter', ...args);
};
//拖拽离开某个节点时触发的事件
//共三个参数，依次为：被拖拽节点对应的 Node、所离开节点对应的 Node、event
const onNodeDragLeave = (...args: any[]) => {
	emits('node-drag-leave', ...args);
};
//在拖拽节点时触发的事件（类似浏览器的 mouseover 事件）
//共三个参数，依次为：被拖拽节点对应的 Node、当前进入节点对应的 Node、event
const onNodeDragOver = (...args: any[]) => {
	emits('node-drag-over', ...args);
};
//拖拽结束时（可能未成功）触发的事件
//共四个参数，依次为：被拖拽节点对应的 Node、结束拖拽时最后进入的节点（可能为空）、被拖拽节点的放置位置（before、after、inner）、event
const onNodeDragEnd = (...args: any[]) => {
	emits('node-drag-end', ...args);
};
//-----------------------方法-------------------------------------------------//
//为节点设置新数据，只有当设置 node-key 属性的时候才可用
//(key, data) 接收两个参数: 1. 节点的 key 2. 新数据
const updateKeyChildren = (key: string | number, data: any) => {
	treeRef.value!.updateKeyChildren(key, data);
};
//如果节点可以被选中，(show-checkbox 为 true), 本方法将返回当前选中节点的数组
//(leafOnly, includeHalfChecked) 接收两个布尔类型参数: 1. 默认值为 false. 若参数为 true, 它将返回当前选中节点的子节点 2. 默认值为 false. 如果参数为 true, 返回值包含半选中节点数据
const getCheckedNodes = (leafOnly: false, includeHalfChecked = false) => {
	return treeRef.value!.getCheckedNodes(leafOnly, includeHalfChecked);
};
//设置目前勾选的节点，使用此方法必须提前设置 node-key 属性  要选中的节点构成的数组
const setCheckedNodes = (keys: []) => {
	treeRef.value!.setCheckedNodes(keys);
};
//若节点可用被选中 (show-checkbox 为 true), 它将返回当前选中节点 key 的数组
//(leafOnly) 接收一个布尔类型参数，默认为 false. 如果参数是 true, 它只返回当前选择的子节点数组。
const getCheckedKeys = (leafOnly: false) => {
	return treeRef.value!.getCheckedKeys(leafOnly);
};
//设置目前选中的节点，使用此方法必须设置 node-key 属性
//(keys, leafOnly) 接收两个参数: 1. 一个需要被选中的多节点 key 的数组 2. 一个布尔类型参数，默认为 false. 如果参数是 true, 它只返回当前选择的子节点数组。
const setCheckedKeys = (keys: [], leafOnly = false) => {
	treeRef.value!.setCheckedKeys(keys, leafOnly);
};
//设置节点是否被选中, 使用此方法必须设置 node-key 属性
//(key/data, checked, deep) 接收三个参数: 1. 要选中的节点的 key 或者数据 2. 一个布尔类型参数表明是否选中. 3. 一个布尔类型参数表明是否递归选中子节点
const setChecked = (key: string | number, checked: boolean, deep: boolean) => {
	treeRef.value!.setChecked(key, checked, deep);
};
//如果节点可用被选中 (show-checkbox 为 true), 它将返回当前半选中的节点组成的数组
const getHalfCheckedNodes = () => {
	return treeRef.value!.getHalfCheckedNodes();
};
//若节点可被选中(show-checkbox 为 true)，则返回目前半选中的节点的 key 所组成的数组
const getHalfCheckedKeys = () => {
	return treeRef.value!.getHalfCheckedKeys();
};
//返回当前被选中节点的数据 (如果没有则返回 null)
const getCurrentKey = () => {
	return treeRef.value!.getCurrentKey();
};
//返回当前被选中节点的数据 (如果没有则返回 null)
const getCurrentNode = () => {
	return treeRef.value!.getCurrentNode();
};
//通过 key 设置某个节点的当前选中状态，使用此方法必须设置 node-key  属性
//(key, shouldAutoExpandParent=true) 1. 待被选节点的 key， 如果为 null, 取消当前选中的节点 2. 是否自动展开父节点
const setCurrentKey = (key: string | number, shouldAutoExpandParent = true) => {
	treeRef.value!.setCurrentKey(key, shouldAutoExpandParent);
};
//设置节点为选中状态，使用此方法必须设置 node-key 属性
//(node, shouldAutoExpandParent=true) 1. 待被选中的节点 2. 是否展开父节点
const setCurrentNode = (node: any, shouldAutoExpandParent = true) => {
	treeRef.value!.setCurrentNode(node, shouldAutoExpandParent);
};
//	根据 data 或者 key 拿到 Tree 组件中的 node
//(data) 节点的 data 或 key
const getNode = (data: any) => {
	return treeRef.value!.getNode(data);
};
//删除 Tree 中的一个节点，使用此方法必须设置 node-key 属性
//(data) 要删除的节点的 data 或者 node 对象
const remove = (node: any) => {
	treeRef.value!.remove(node);
};
//为 Tree 中的一个节点追加一个子节点
//(data, parentNode) 1. 要追加的子节点的 data 2. 父节点的 data, key 或 node
const append = (data: any, parentNode: any) => {
	treeRef.value!.append(data, parentNode);
};
//在 Tree 中给定节点前插入一个节点
//(data, refNode) 1. 要增加的节点的 data 2. 参考节点的 data, key 或 node
const insertBefore = (data: any, refNode: any) => {
	treeRef.value!.insertBefore(data, refNode);
};
//在 Tree 中给定节点后插入一个节点
//(data, refNode) 1. 要增加的节点的 data 2. 参考节点的 data, key 或 node
const insertAfter = (data: any, refNode: any) => {
	treeRef.value!.insertAfter(data, refNode);
};
//将方法暴露出去
defineExpose({
	updateKeyChildren,
	getCheckedNodes,
	setCheckedNodes,
	getCheckedKeys,
	setCheckedKeys,
	setChecked,
	getHalfCheckedNodes,
	getHalfCheckedKeys,
	getCurrentKey,
	getCurrentNode,
	setCurrentKey,
	setCurrentNode,
	getNode,
	remove,
	append,
	insertBefore,
	insertAfter,
  treeList,
	query,
});
onMounted(() => {
	nextTick(() => {
		query();
	});
});
</script>
<style lang="scss" scoped>
:deep(.el-tree-node__content) {
	height: 30px;
}
.search-tree-color {
	color: var(--el-color-primary);
}
.more-tree-color {
	color: #9b9da1;
}
</style>
